#pragma once
#define CFG_IGNORE_TESTMEMORYPOOL
#ifndef CFG_IGNORE_TESTMEMORYPOOL
#include <stdio.h>
#include <stdlib.h>
#include <memory>
#include <assert.h>
#include <iostream>
//////////////////////////////////////////////////////////////////////////
///DEFINITION OF THE POINT TYPES
/// A Point = Saves information about the allocated/free portion. Used for fast memory lookup.
/// B Point = Tells how long is one single allocation block(one allocation). Used for deallocation
/// C Point = This is every chunk info.
typedef struct
{
	unsigned short bytes_used;
}chunk_info;

typedef unsigned char uchar;
typedef unsigned short ushort;

class MemoryPoolSystem;
class MemoryPool
{
public:
	MemoryPool() { m_pnext = NULL;m_chunks_used = 0; }
	~MemoryPool() {}
	unsigned char * m_pool_start; // where does the pool start?
	unsigned char * m_chunkinfo_start;
	ushort *		m_next_alloc[2];
	unsigned int m_chunks;
	unsigned int m_chunk_size;
	unsigned int m_chunks_used;
	//Pool Public Functions
	void SetUpChunkInfo();
	void DefragmentChunkInfo();
	void* Allocate(size_t size);
	void Deallocate(void* chunk);
	//Information functions
	unsigned int GetUsedBytes();
	unsigned int GetFreeBytes();
	unsigned int GetBytesCap();
	void PrintChunkInfo();

	//Private ChunkInfo Functions
	uchar* FindFreeBlock(size_t size, ushort** last_apoint);
	uchar* FindFreeBlockFrom(uchar* pfrom, size_t size, ushort** last_apoint);
	bool   SetBlockFree(uchar* block);
	bool   SetBlockAPointsFreed(uchar* block, size_t chunks);
	bool   SetBlockBPointsFreed(uchar* block, size_t chunks);

	bool   SetBlockAllocated(ushort* last_apoint, uchar* block, size_t size);
	bool   SetBlockAPointsAllocated(ushort* last_apoint, uchar* block, size_t chunks);
	bool   SetBlockBPointsAllocated(uchar* block, size_t chunks);
	//Private Helper ChunkInfo Functions
	uchar* GetDataPtr(uchar * info);
	uchar* GetInfoPtr(uchar * data);
	ushort* FindAPointByCPoint(ushort* cpoint); // find the closed info poit which is behind the passed ptr


	//Bit Manipulation Functions
	static ushort SetCertainBits(uchar bit_count, uchar start, ushort value, ushort source);
	static size_t SetCertainBits(uchar bit_count, uchar start, size_t value, size_t source);
	static ushort GetCertainBits(uchar bit_count, uchar start, ushort source);
	static size_t GetCertainBits(uchar bit_count, uchar start, size_t source);

	//Next linked list pool
	MemoryPool * m_pnext;
};
class MemoryPoolSystem
{
	friend MemoryPool;
public:
	MemoryPoolSystem(bool automatic_pool_generation, unsigned int default_chunk_count, unsigned char default_chunk_size);
	~MemoryPoolSystem() { RemoveAllPools(); }

	bool m_automatic_pool_generation;
	unsigned char m_default_chunk_size;
	unsigned int m_default_chunk_count;
	MemoryPool * m_pfirst;

	//for now, use just one fixed memory pool;
	MemoryPool* GenerateNewPool(unsigned int chunk_count, unsigned char chunk_size);
	void AddPool(MemoryPool * pool);
	void RemovePool(MemoryPool * pool);
	void RemoveAllPools();

	void* Allocate(unsigned int size);
	void  Deallocate(void* chunk);
	unsigned int GetTotalBytesUsed();
	unsigned int GetChunkSizesOnly();
};

#endif